/*
 * @Author: wangchao
 * @Date: 2024-08-22 11:50:19
 * @LastEditors: wangchao
 * @LastEditTime: 2024-09-25 13:49:54
 * @FilePath: \JD-RTT-Driver\applications\u_rtc.c
 * @Description:
 * Copyright (c) 2024 by Bingshan Guardian, All Rights Reserved.
 */

#include "u_rtc.h"

#define DBG_TAG "RTC"
#define DBG_LVL DBG_INFO
#include <rtdbg.h>

#define I2C_BUS_NAME "i2c2"
#define PCF8563_ADDR (0xA2 >> 1)

#define PCF8563_REG_TIME 0x02

static struct rt_i2c_bus_device* rtc_iic_bus;

static rt_uint8_t bcd2dec(rt_uint8_t bcd)
{
    return (bcd >> 4) * 10 + (bcd & 0x0F);
}

static rt_uint8_t dec2bcd(rt_uint8_t decimal)
{
    return (((decimal / 10) << 4) | (decimal % 10));
}

void rtc_bus_init(void)
{
    rtc_iic_bus = (struct rt_i2c_bus_device*)rt_device_find(I2C_BUS_NAME);
    if (rtc_iic_bus == RT_NULL)
    {
        rt_kprintf("I2C bus device %s not found!\n", I2C_BUS_NAME);
        return;
    }
    LOG_I("rtc bus init success");
}

static rt_err_t rtc_set_one_reg(rt_uint8_t reg, const rt_uint8_t data)
{
    struct rt_i2c_msg msgs;
    rt_uint8_t buf[2] = {reg, data};
    msgs.addr = PCF8563_ADDR;
    msgs.flags = RT_I2C_WR;
    msgs.buf = buf;
    msgs.len = 2;
    return rt_i2c_transfer(rtc_iic_bus, &msgs, 1);
}

static rt_err_t rtc_read_one_reg(rt_uint8_t reg, rt_uint8_t* data)
{
    struct rt_i2c_msg msgs[2];
    rt_uint8_t buf[1] = {reg};
    msgs[0].addr = PCF8563_ADDR;
    msgs[0].flags = RT_I2C_WR;
    msgs[0].buf = buf;
    msgs[0].len = 1;
    msgs[1].addr = PCF8563_ADDR;
    msgs[1].flags = RT_I2C_RD;
    msgs[1].buf = data;
    msgs[1].len = 1;
    return rt_i2c_transfer(rtc_iic_bus, msgs, 2);
}

static rt_size_t rtc_read_reg(rt_uint8_t reg, rt_uint8_t* data, rt_uint8_t len)
{
    struct rt_i2c_msg msgs[2];
    rt_uint8_t buf[1] = {reg};
    msgs[0].addr = PCF8563_ADDR;
    msgs[0].flags = RT_I2C_WR;
    msgs[0].buf = buf;
    msgs[0].len = 1;
    msgs[1].addr = PCF8563_ADDR;
    msgs[1].flags = RT_I2C_RD;
    msgs[1].buf = data;
    msgs[1].len = len;
    return rt_i2c_transfer(rtc_iic_bus, msgs, 2);
}

void rtc_set_time(struct app_tm* tms)
{
    rt_uint8_t data = 0;
    //
    if (tms->tm_sec > 59)
    {
        tms->tm_sec = 59;
    }
    if (tms->tm_min > 59)
    {
        tms->tm_min = 59;
    }
    if (tms->tm_hour > 23)
    {
        tms->tm_hour = 23;
    }
    if (tms->tm_mday > 31)
    {
        tms->tm_mday = 31;
    }
    if (tms->tm_mon > 12)
    {
        tms->tm_mon = 12;
    }
    if (tms->tm_year > 99)
    {
        tms->tm_year = 99;
    }
    // set sec min hour
    data = dec2bcd(tms->tm_sec) & 0x7F;
    rtc_set_one_reg(SECOND_DATA_REG, data);
    data = dec2bcd(tms->tm_min) & 0x7F;
    rtc_set_one_reg(MINUTE_DATA_REG, data);
    data = dec2bcd(tms->tm_hour) & 0x3F;
    rtc_set_one_reg(HOUR_DATA_REG, data);
    // set year mon day
    data = dec2bcd(tms->tm_mday);
    rtc_set_one_reg(DAY_DATA_REG, data);
    data = dec2bcd(tms->tm_mon);
    rtc_set_one_reg(MONTH_DATA_REG, data);
    data = dec2bcd(tms->tm_year);
    rtc_set_one_reg(YEAR_DATA_REG, data);
}

rt_size_t rtc_get_time(struct app_tm* tms)
{
    rt_uint8_t data[7] = {0}, tm = 0;
    rt_size_t ret_size = rtc_read_reg(PCF8563_REG_TIME, data, 7);
    tm = bcd2dec(data[0] & 0x7f);
    tms->tm_sec = tm;
    tm = bcd2dec(data[1] & 0x7f);
    tms->tm_min = tm;
    tm = bcd2dec(data[2] & 0x3f);
    tms->tm_hour = tm;
    tm = bcd2dec(data[3] & 0x3f);
    tms->tm_mday = tm;
    tm = bcd2dec(data[5] & 0x1F);
    tms->tm_mon = tm;
    tm = bcd2dec(data[6] & 0xfF);
    tms->tm_year = tm + 2000;
    return ret_size;
}

void extract_date_time(char* datetime, int* year, int* month, int* day, int* hour, int* minute, int* second)
{
    // 检查字符串长度是否足够
    if (strlen(datetime) < 14)
    {
        printf("Error: Invalid datetime string!\n");
        return;
    }
    // 提取年月日时分秒
    sscanf(datetime, "%4d%2d%2d%2d%2d%2d", year, month, day, hour, minute, second);
}

rt_bool_t check_datetime_format(char* datetime)
{
    int len = strlen(datetime);
    // 检查字符串长度是否满足要求
    if (len != 14)
    {
        return RT_FALSE;
    }
    // 检查字符串是否只包含数字字符
    for (int i = 0; i < len; ++i)
    {
        if (!isdigit(datetime[i]))
        {
            return RT_FALSE;
        }
    }
    // 返回1表示满足要求
    return RT_TRUE;
}

void set_time(int argc, void** argv)
{
    if (argc == 2)
    {
        if (check_datetime_format(argv[1]))
        {
            int year, month, day, hour, minute, second;
            extract_date_time(argv[1], &year, &month, &day, &hour, &minute, &second);
            struct app_tm trtc;
            trtc.tm_year = year - 2000;
            trtc.tm_mon = month;
            trtc.tm_mday = day;
            trtc.tm_hour = hour;
            trtc.tm_min = minute;
            trtc.tm_sec = second;
            LOG_I("set-time:%04d-%02d-%02d %02d:%02d:%02d", trtc.tm_year, trtc.tm_mon, trtc.tm_mday, trtc.tm_hour, trtc.tm_min, trtc.tm_sec);
            rtc_set_time(&trtc);
        }
        else
        {
            LOG_E("The time format is incorrect.");
            return;
        }
    }
    else
    {
        LOG_E("The time format is incorrect.");
        return;
    }
}

#if 0
INIT_APP_EXPORT(rtc_bus_init);
#endif

void print_time(void)
{
    struct app_tm app_tms;
    rtc_get_time(&app_tms);
    LOG_I("current-time:%04d-%02d-%02d %02d:%02d:%02d", app_tms.tm_year, app_tms.tm_mon, app_tms.tm_mday, app_tms.tm_hour, app_tms.tm_min, app_tms.tm_sec);
}

void get_current_time(struct app_tm* app_tms)
{
    rtc_get_time(app_tms);
}

// 判断是否为闰年
static int is_leap_year(int year)
{
    return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
}

// 获取月份的天数
static int get_days_in_month(int year, int month)
{
    int days_per_month[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    if (month == 1 && is_leap_year(year))
    {  // 2月（tm_mon为1表示2月）
        return 29;
    }
    return days_per_month[month];
}

// 计算两个时间之间的秒数差
static int calculate_difference_in_seconds(const struct app_tm* old_time, const struct app_tm* new_time)
{
    int days_in_month = get_days_in_month(new_time->tm_year, new_time->tm_mon);
    int carry = 0;  // 进位标志
    int diff_seconds = new_time->tm_sec - old_time->tm_sec;

    if (diff_seconds < 0)
    {
        diff_seconds += 60;
        carry = 1;  // 需要从分钟进位
    }
    else
    {
        carry = 0;
    }

    int diff_minutes = new_time->tm_min - old_time->tm_min - carry;
    if (diff_minutes < 0)
    {
        diff_minutes += 60;
        carry = 1;  // 需要从小时进位
    }
    else
    {
        carry = 0;
    }

    int diff_hours = new_time->tm_hour - old_time->tm_hour - carry;
    if (diff_hours < 0)
    {
        diff_hours += 24;
        carry = 1;  // 需要从天进位
    }
    else
    {
        carry = 0;
    }

    int diff_days = new_time->tm_mday - old_time->tm_mday - carry;
    if (diff_days < 0)
    {
        diff_days += days_in_month;
        carry = 1;  // 需要从月进位
    }
    else
    {
        carry = 0;
    }

    int diff_months = new_time->tm_mon - old_time->tm_mon - carry;
    if (diff_months < 0)
    {
        diff_months += 12;
        carry = 1;  // 需要从年进位
    }
    else
    {
        carry = 0;
    }

    int diff_years = new_time->tm_year - old_time->tm_year - carry;

    // 如果年、月、天、小时、分钟均为0，且秒在2以内，则返回1
    if (diff_years == 0 && diff_months == 0 && diff_days == 0 && diff_hours == 0 && diff_minutes == 0 && diff_seconds <= 2)
    {
        return 1;
    }

    return 0;
}

// 比较两个时间是否在2秒以内
int compare_time_within_2_seconds(const struct app_tm* old_time, const struct app_tm* new_time)
{
    return calculate_difference_in_seconds(old_time, new_time);
}

//
struct app_tm app_cur_time;
static rt_uint8_t visit_count = 0;
//
void app_rtc_service(void)
{
    visit_count++;
    if (visit_count > 5)
    {
        visit_count = 0;
        rtc_get_time(&app_cur_time);
    }
}

#if 0
MSH_CMD_EXPORT(set_time, set rtc time);
MSH_CMD_EXPORT(print_time, get rtc time);
#endif